package com.heima.schedule.service.impl;

import com.heima.schedule.redis.impl.UpdateLocakTimeoutTask;
import com.heima.schedule.service.RedisLock;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.ThreadUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;


import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * 分布式锁功能接口实现类
 */
@Slf4j
@Service
public class RedisLockImpl implements RedisLock {

    private StringRedisTemplate stringRedisTemplate;

    private ThreadLocal<String> threadLocal=new ThreadLocal<>();
    public RedisLockImpl(StringRedisTemplate stringRedisTemplate){
        this.stringRedisTemplate=stringRedisTemplate;
    }

    @Override
    public Boolean tryLock(Long awaitTime,String key, long timeout, TimeUnit unit) {
        //生成线程的唯一标识ID
        String uuid= UUID.randomUUID().toString().replace("_","");

        threadLocal.set(uuid);
        Boolean isLock = stringRedisTemplate.opsForValue().setIfAbsent(key, uuid, timeout, unit);

        //开启一个子线程,由于子线程不断续约，锁释放后再将子线程销毁
        if(isLock){
            new Thread(new UpdateLocakTimeoutTask(stringRedisTemplate,uuid,timeout,unit,key)).start();
        }else{
            int count=0;
            log.info("获取锁失败，开始重试用,重试次数{}",count);
            long await=0;
            awaitTime=unit.toMillis(awaitTime);
            while(awaitTime>=await){
                try {
                    //获取锁失败,休眠一段时间100毫秒
                    Thread.sleep(100);
                    await+=100;
                    count++;
                    isLock=stringRedisTemplate.opsForValue().setIfAbsent(key, uuid, timeout, unit);
                    if(isLock){
                        log.info("重试成功,重试次数:{}",count);
                        break;
                    }
                    log.info("重试失败,重试次数:{}",count);
                } catch (InterruptedException e) {
                    throw  new RuntimeException(e);
                }

            }

        }
        return isLock;
    }


    @Override
    public void releaseLock(String key) {
        //从redis中获取锁的唯一标识
//        String value = stringRedisTemplate.opsForValue().get(key);
        //获取当前线程唯一标识
        String uuid=threadLocal.get();
        //获取持有锁线程唯一标识
        String lock_uuid = stringRedisTemplate.opsForValue().get(key);
        //将redis中获取的锁标识与当前线程的标识作比较，若相同则才能释放锁
        if(StringUtils.isNotEmpty(uuid)&&StringUtils.isEmpty(lock_uuid)&&uuid.equals(lock_uuid)){
            stringRedisTemplate.delete(key);
            //停止线程 interrupt();
            //从redis中获取线程id
            String threadId = stringRedisTemplate.opsForValue().get(lock_uuid);
            if(StringUtils.isNotEmpty(threadId)){
                //获取线程对象
                Thread thread= ThreadUtils.findThreadById(Long.valueOf(threadId));
                //终止贤臣
                thread.interrupt();
            }
        }

    }


}
